package com.yf.ability.face.provides.tencent.service.impl;

import com.alibaba.fastjson.JSON;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.iai.v20200303.IaiClient;
import com.tencentcloudapi.iai.v20200303.models.*;
import com.yf.ability.config.dto.CfgPropDTO;
import com.yf.ability.config.enums.ConfigType;
import com.yf.ability.config.enums.ProviderType;
import com.yf.ability.config.service.CfgPropService;
import com.yf.base.api.exception.ServiceException;
import com.yf.ability.face.provides.tencent.config.TencentFaceConfig;
import com.yf.ability.face.enums.FaceImageType;
import com.yf.ability.face.service.ThirdFaceService;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 腾讯云人脸识别实现
 * @author
 */
@Log4j2
@Service("tencentFaceService")
public class TencentFaceServiceImpl implements ThirdFaceService {


    @Autowired
    private CfgPropService cfgPropService;

    @Override
    public void addFace(String imageType, String image, String userId) {

        TencentFaceConfig config = this.getConfig();
        this.checkGroup(config.getGroupId());
        try{

            // 实例化一个请求对象,每个接口都会对应一个request对象
            CreatePersonRequest req = new CreatePersonRequest();
            req.setGroupId(config.getGroupId());
            req.setPersonName(userId);
            req.setPersonId(userId);

            // BASE64编码
            if(FaceImageType.BASE64.equals(imageType)){
                req.setImage(image);
            }else{
                // URL地址
                req.setUrl(image);
            }

            // 创建请求对象
            CreatePersonResponse resp = this.getClient().CreatePerson(req);
            // 输出json格式的字符串回包
            log.info("tx添加人脸用户：{}", CreatePersonResponse.toJsonString(resp));
        } catch (TencentCloudSDKException e) {

            // 如果人员存在，则删除再建
            if("InvalidParameterValue.PersonIdAlreadyExist".equals(e.getErrorCode())){
                this.updateFace(imageType, image, userId);
                return;
            }
            throw new ServiceException(e.getMessage());
        }

    }

    @Override
    public void deleteFace(String userId) {

        try{
            // 实例化一个请求对象,每个接口都会对应一个request对象
            DeletePersonRequest req = new DeletePersonRequest();
            req.setPersonId(userId);
            // 返回的resp是一个CreatePersonResponse的实例，与请求对象对应
            DeletePersonResponse resp = this.getClient().DeletePerson(req);
            // 输出json格式的字符串回包
            log.info("tx删除人脸用户：", CreatePersonResponse.toJsonString(resp));
        } catch (TencentCloudSDKException e) {
            // 如果人脸不存在，忽略即可，无需抛出异常
            if(!"InvalidParameterValue.GroupIdNotExist".equals(e.getErrorCode())
                    && !"InvalidParameterValue.PersonIdNotExist".equals(e.getErrorCode())){
                throw new ServiceException("人脸删除失败：" + e.getMessage());
            }
        }
    }

    @Override
    public void updateFace(String imageType, String image, String userId) {
        // 先删除
        this.deleteFace(userId);
        // 再增加
        this.addFace(imageType, image, userId);
    }

    /**
     * 搜索人脸
     * @param imageType
     * @param image
     * @return
     */
    @Override
    public String searchFace(String imageType, String image){

        try {

            // 获取配置
            TencentFaceConfig cfg = this.getConfig();

            // 实例化一个请求对象,每个接口都会对应一个request对象
            SearchPersonsRequest req = new SearchPersonsRequest();
            String[] groupIds = {cfg.getGroupId()};
            req.setGroupIds(groupIds);

            // BASE64编码
            if(FaceImageType.BASE64.equals(imageType)){
                req.setImage(image);
            }else{
                // URL地址
                req.setUrl(image);
            }

            // 返回的resp是一个SearchPersonsResponse的实例，与请求对象对应
            SearchPersonsResponse resp = this.getClient().SearchPersons(req);

           // 输出json格式的字符串回包
           log.info("人脸识别结果：" + JSON.toJSONString(resp));


            Long num = resp.getPersonNum();
            if(num!=null && num.equals(0L)){
                throw new ServiceException("识别失败，未找到匹配的人脸！");
            }

            Result [] results = resp.getResults();
            if(results==null || results.length==0){
                throw new ServiceException("识别失败，未找到匹配的人脸！");
            }

            Candidate [] users = results[0].getCandidates();
            String userId = null;
            Float score = -1f;
            for(Candidate cd: users){
                // 大于85分一般就可以认定是本人
                if(cd.getScore() > 85 && cd.getScore()> score){
                    userId = cd.getPersonId();
                    score = cd.getScore();
                }
            }

            if(userId == null){
                throw new ServiceException("识别失败，未找到匹配的人脸！");
            }

            return userId;
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
            throw new ServiceException("人脸识别失败："+e.getErrorCode());
        }


    }

    @Override
    public void mergeFace(boolean isAdd, String oldFace, String newFace, String userId) {

        // 添加模式
        if(isAdd){
            if(!StringUtils.isBlank(newFace)){
                // 直接添加
                this.addFace(FaceImageType.URL, newFace, userId);
            }
        }else{

            // 清空，删除人脸
            if(StringUtils.isBlank(newFace) && !StringUtils.isBlank(oldFace)){
                this.deleteFace(userId);
                return;
            }

            // 添加过，更新
            if(!StringUtils.isBlank(newFace) && !StringUtils.isBlank(oldFace)){
                this.updateFace(FaceImageType.URL, newFace, userId);
                return;
            }

            // 未添加过，增加
            if(!StringUtils.isBlank(newFace) && StringUtils.isBlank(oldFace)){
                this.addFace(FaceImageType.URL, newFace, userId);
            }
        }
    }

    /**
     * 校验人脸库，如果不存在则创建，存在则什么也不干
     * @param groupId
     */
    private void checkGroup(String groupId){

        try{
            // 实例化一个请求对象,每个接口都会对应一个request对象
            GetGroupInfoRequest req = new GetGroupInfoRequest();
            req.setGroupId(groupId);
            // 返回的resp是一个GetGroupInfoResponse的实例，与请求对象对应
            GetGroupInfoResponse resp = this.getClient().GetGroupInfo(req);
            // 输出json格式的字符串回包
            log.info("tx查询人脸库：", GetGroupInfoResponse.toJsonString(resp));
        } catch (TencentCloudSDKException e) {

            // 人脸库不存在，创建
            if("InvalidParameterValue.GroupIdNotExist".equals(e.getErrorCode())){
                this.createGroup(groupId);
                return;
            }
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 创建一个人脸库
     * @param groupId
     */
    private void createGroup(String groupId){

        try{
            // 实例化一个请求对象,每个接口都会对应一个request对象
            CreateGroupRequest req = new CreateGroupRequest();
            req.setGroupName("考试_"+ RandomStringUtils.randomAlphabetic(8));
            req.setGroupId(groupId);
            req.setFaceModelVersion("3.0");
            // 返回的resp是一个CreateGroupResponse的实例，与请求对象对应
            CreateGroupResponse resp = this.getClient().CreateGroup(req);
            // 输出json格式的字符串回包
            log.info("tx创建人脸库：", CreateGroupResponse.toJsonString(resp));
        } catch (TencentCloudSDKException e) {
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 获取配置文件
     * @return
     */
    private TencentFaceConfig getConfig(){
        CfgPropDTO dto = cfgPropService.detail(ConfigType.FACE, ProviderType.QCLOUD);
        TencentFaceConfig cfg = JSON.parseObject(dto.getData(), TencentFaceConfig.class);
        return cfg;
    }


    /**
     * 获取API接口
     * @return
     */
    private IaiClient getClient(){

        // 获取配置
        TencentFaceConfig cfg = this.getConfig();

        // 实例化一个认证对象，入参需要传入腾讯云账户secretId，secretKey,此处还需注意密钥对的保密
        // 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取
        Credential cred = new Credential(cfg.getSecretId(), cfg.getSecretKey());
        // 实例化一个http选项，可选的，没有特殊需求可以跳过
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint("iai.tencentcloudapi.com");
        // 实例化一个client选项，可选的，没有特殊需求可以跳过
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        // 实例化要请求产品的client对象,clientProfile是可选的
        IaiClient client = new IaiClient(cred, cfg.getRegion(), clientProfile);

        return client;
    }
}
